﻿/*
 * This file is part of MonoStrategy.
 *
 * Copyright (C) 2010-2011 Christoph Husse
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors: 
 *      # Christoph Husse
 * 
 * Also checkout our homepage: http://monostrategy.codeplex.com/
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using MonoStrategy.RenderSystem;
using System.Xml;
using System.Xml.Serialization;
using System.Runtime.Serialization;

namespace MonoStrategy
{
    public class BuildingInspector
    {
        public static BuildingInspector Instance {get; private set;}

        public BuildTask Task { get; private set; }
        public BaseBuilding Building { get; private set; }
        public GUIBindings Binding { get; private set; }

        private Button Btn_BoostPrio;
        private Button Btn_Produce;
        private Button Btn_SetProdRange;
        private Button Btn_SetTarget;
        private Button Btn_Destroy;
        private Image OI_BuildingImage;
        private Label OI_BuildingName;
        private Label OI_BuildProgress;
        private ListBox OI_ResourceQueries;
        private ListBox OI_ResourceProviders;
        private Control OI_StackInfo;
        private Control OI_MarketInfo;
        private ListBox OI_MarketResources;
        private ListBox OI_MarketTransports;
        private Control QueryInfo;
        private Control ProviderInfo;
        private VisualWorkingArea m_WorkingArea = null;

        public static void Show(GUIBindings inBindings, BaseBuilding inBuilding, BuildTask inTask)
        {
            Abort();

            Instance = new BuildingInspector(inBindings, inBuilding, inTask);
        }

        public static void Abort()
        {
            if (Instance == null)
                return;

            Instance.Dispose();

            Instance = null;
        }

        public static void Close()
        {
            if (Instance != null)
                Instance.Save();

            Abort();
        }

        private void Save()
        {
            if (m_WorkingArea != null)
                Program.Map.SetWorkingArea(Building, m_WorkingArea.Position.ToPoint());
        }

        private void Dispose()
        {
            Binding.MainMenu.IsVisible = true;
            Binding.ObjectInspector.IsVisible = false;

            if (m_WorkingArea != null)
            {
                Program.TerrainRenderer.OnMouseGridMove -= TerrainRenderer_OnMouseGridMove;

                m_WorkingArea.Dispose();
                m_WorkingArea = null;
            }

            // unregister events
            Btn_BoostPrio.OnClick -= Btn_BoostPrio_OnClick;
            Btn_Produce.OnClick -= Btn_Produce_OnClick;
            Btn_SetProdRange.OnClick -= Btn_SetProdRange_OnClick;
            Btn_SetTarget.OnClick -= Btn_SetTarget_OnClick;
            Btn_Destroy.OnClick -= Btn_Destroy_OnClick;

            Program.Map.OnRemoveBuildTask -= Map_OnRemoveBuildTask;
            Program.Map.OnRemoveBuilding -= Map_OnRemoveBuilding;
        }

        private BuildingInspector(GUIBindings inBindings, BaseBuilding inBuilding, BuildTask inTask)
        {
            Binding = inBindings;
            Building = inBuilding;
            Task = inTask;

            OI_ResourceQueries = Binding.FindControl<ListBox>("#list:OI_ResourceQueries");
            OI_ResourceProviders = Binding.FindControl<ListBox>("#list:OI_ResourceProviders");
            OI_BuildingName = Binding.FindControl<Label>("#label:OI_BuildingName");
            OI_BuildingImage = Binding.FindControl<Image>("#image:OI_BuildingImage");
            OI_StackInfo = Binding.FindControl<Control>("#ctrl:OI_StackInfo");
            OI_MarketInfo = Binding.FindControl<Control>("#ctrl:OI_MarketInfo");
            OI_MarketResources = Binding.FindControl<ListBox>("#list:OI_MarketResources");
            OI_MarketTransports = Binding.FindControl<ListBox>("#list:OI_MarketTransports");
            OI_BuildProgress = Binding.FindControl<Label>("#label:OI_BuildProgress");

            Btn_BoostPrio = Binding.ObjectInspector.FindControl("Btn_BoostPrio") as Button;
            Btn_Produce = Binding.ObjectInspector.FindControl("Btn_Produce") as Button;
            Btn_SetProdRange = Binding.ObjectInspector.FindControl("Btn_SetProdRange") as Button;
            Btn_SetTarget = Binding.ObjectInspector.FindControl("Btn_SetTarget") as Button;
            Btn_Destroy = Binding.ObjectInspector.FindControl("Btn_Destroy") as Button;
            QueryInfo = Binding.ObjectInspector.FindControl("QueryInfo");
            ProviderInfo = Binding.ObjectInspector.FindControl("ProviderInfo");

            Program.Map.OnRemoveBuildTask += Map_OnRemoveBuildTask;
            Program.Map.OnRemoveBuilding += Map_OnRemoveBuilding;

            Btn_BoostPrio.OnClick += Btn_BoostPrio_OnClick;
            Btn_Produce.OnClick += Btn_Produce_OnClick;
            Btn_SetProdRange.OnClick += Btn_SetProdRange_OnClick;
            Btn_SetTarget.OnClick += Btn_SetTarget_OnClick;
            Btn_Destroy.OnClick += Btn_Destroy_OnClick;

            Update();

            Binding.MainMenu.IsVisible = false;
            Binding.ObjectInspector.IsVisible = true;
        }

        void Map_OnRemoveBuilding(GameMap inSender, BaseBuilding inBuilding)
        {
            if (inBuilding == Building)
                Abort();
        }

        void Map_OnRemoveBuildTask(GameMap inSender, BuildTask inTask)
        {
            if (inTask == Task)
                Abort();
        }

        void Btn_Destroy_OnClick(Button inSender)
        {
            if (Task != null)
                Program.Map.RemoveBuildTask(Task);
            else
                Program.Map.RemoveBuilding(Building);
        }

        private void Btn_BoostPrio_OnClick(Button inSender)
        {
            if (Task != null)
            {
                inSender.IsDown = false;
                Program.Map.RaiseTaskPriority(Task);
            }
            else
            {
                if(inSender.IsDown)
                    Program.Map.RaiseBuildingPriority(Building);
                else
                    Program.Map.LowerBuildingPriority(Building);
            }
        }

        private void Btn_Produce_OnClick(Button inSender)
        {
            if (Task != null)
                Program.Map.SetTaskSuspended(Task, isSuspended: inSender.IsDown);
            else
                Program.Map.SetBuildingSuspended(Building, isSuspended: inSender.IsDown);
        }

        private void Btn_SetProdRange_OnClick(Button inSender)
        {
            // show current working area
            m_WorkingArea = new VisualWorkingArea(Program.TerrainRenderer, Building.WorkingArea, (Building as IBuildingWithWorkingArea).WorkingRadius);

            Program.TerrainRenderer.OnMouseGridMove += TerrainRenderer_OnMouseGridMove;
        }

        void TerrainRenderer_OnMouseGridMove(TerrainRenderer inSender, Point inNewGridXY)
        {
            if (m_WorkingArea != null)
            {
                m_WorkingArea.Position = CyclePoint.FromGrid(inNewGridXY);
            }
        }

        private void Btn_SetTarget_OnClick(Button inSender)
        {
        }


        public void Update()
        {
            if (Task != null)
                UpdateBuildTask();
            else if(Building is MarketBuilding)
                UpdateMarketBuilding();
            else if ((Building is InputOutputBuilding) || (Building is OutputOnlyBuilding) || (Building is SettlerBuilding))
                UpdateProductionBuilding();
        }

        private void DefaultBuildingUpdate()
        {
            OI_ResourceQueries.Clear();
            OI_ResourceProviders.Clear();

            OI_BuildingName.Text = Building.Config.Name;
            OI_BuildingImage.SourceString = "Race/Romans/Buildings/" + Building.Config.AnimationClass + ".png";

            OI_StackInfo.IsVisible = true;
            OI_MarketInfo.IsVisible = false;
            OI_BuildProgress.IsVisible = false;
            Btn_BoostPrio.IsToggleable = true;
            Btn_BoostPrio.IsDown = false;

            QueryInfo.IsVisible = Building.QueriesReadonly.Count() > 0;
            ProviderInfo.IsVisible = Building.ProvidersReadonly.Count() > 0;
        }

        public void UpdateBuildTask()
        {
            DefaultBuildingUpdate();

            Btn_BoostPrio.IsVisible = true;
            Btn_Produce.IsVisible = true;
            Btn_SetProdRange.IsVisible = false;
            Btn_SetTarget.IsVisible = false;
            OI_BuildProgress.IsVisible = true;

            // compute progress
            int progress = (int)(Task.Progress * 50);

            if (Task.IsGraded)
                progress += 50;
            if (Task.IsBuilt)
                progress = 100;

            OI_BuildProgress.Text = progress + "%";

            // visualize queries
            foreach (var query in Task.Queries)
            {
                if (OI_ResourceQueries.Count >= 3)
                    break;

                if (query == null)
                    continue;

                OI_ResourceQueries.AddItem(new ListBoxItem(query.Resource.ToString(), query.Available.ToString(), query.VirtualCount.ToString()));
            }

            QueryInfo.IsVisible = true;
            ProviderInfo.IsVisible = false;
        }

        private void UpdateMarketBuilding()
        {
            MarketBuilding market = Building as MarketBuilding;
            int btnID = 0;

            DefaultBuildingUpdate();

            Btn_BoostPrio.IsVisible = true;
            Btn_Produce.IsVisible = true;
            Btn_SetProdRange.IsVisible = false;
            Btn_SetTarget.IsVisible = true;

            OI_StackInfo.IsVisible = false;
            OI_MarketInfo.IsVisible = true;

            OI_MarketResources.Clear();
            OI_MarketTransports.Clear();

            foreach (var resVal in Enum.GetValues(typeof(Resource)))
            {
                Resource res = (Resource)resVal;

                if (res == Resource.Max)
                    continue;

                OI_MarketResources.AddItem(new ListBoxItem(res.ToString(), btnID.ToString()));

                (OI_MarketResources.FindControl("Btn_" + btnID) as Button).OnClick += (sender) =>
                {
                    Program.Map.AddMarketTransport(market, res);
                };

                btnID++;
            }

            btnID = 0;

            foreach (var resVal in market.Transports)
            {
                Resource res = (Resource)resVal;

                OI_MarketTransports.AddItem(new ListBoxItem(res.ToString(), btnID.ToString()));
                (OI_MarketTransports.FindControl("Btn_" + btnID) as Button).OnClick += (sender) =>
                {
                    Program.Map.RemoveMarketTransport(market, res);
                };

                btnID++;
            }
        }

        private void UpdateProductionBuilding()
        {
            DefaultBuildingUpdate();

            Btn_BoostPrio.IsVisible = Building.QueriesReadonly.Count() > 0;
            Btn_Produce.IsVisible = Building is ISuspendableBuilding;
            Btn_SetProdRange.IsVisible = Building is IBuildingWithWorkingArea;
            Btn_SetTarget.IsVisible = false;

            foreach (var query in Building.QueriesReadonly)
            {
                if (OI_ResourceQueries.Count >= 3)
                    break;

                if (query == null)
                    continue;

                OI_ResourceQueries.AddItem(new ListBoxItem(query.Resource.ToString(), query.Available.ToString(), query.VirtualCount.ToString()));
            }

            foreach (var prov in Building.ProvidersReadonly)
            {
                if (OI_ResourceProviders.Count >= 6)
                    break;

                if ((prov == null) || (prov.Resource == Resource.Max))
                    continue;

                OI_ResourceProviders.AddItem(new ListBoxItem(prov.Resource.ToString(), prov.Available.ToString(), prov.VirtualCount.ToString()));
            }
        }
    }
}
